#include "push_mysqli.h"

extern void push_db_data(string addr, string query, string error, long execute_micro_time);

void push_mysqli_handler(zend_execute_data *execute_data, zval *return_value, long execute_micro_time, string class_name, string function_name)
{
    uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data);
    if (arg_count)
    {
        // 初始化参数
        string ip = "127.0.0.1";
        string port = "3306";
        string addr = "";
        string sql = "";
        string err = "";
        string query = "";

        zval *mysql_link = ZEND_CALL_ARG(execute_data, 1);

        if (Z_TYPE_P(mysql_link) != IS_OBJECT)
        {
            return;
        }

        zval *z_sql = ZEND_CALL_ARG(execute_data, 2);
        MY_MYSQL *mysql;
        MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_INITIALIZED);

        // 获取数据库地址
        MYSQLND_STRING hostname = mysql->mysql->data->hostname;
        string host = hostname.s;
        int port_i = mysql->mysql->data->port;
        // vector<string> ipport = split(host, ':');
        vector<string> ipport = split(host, ":");
        ip = ipport.size() > 0 ? ipport[0] : "";
        port = to_string(port_i);
        addr = ip + ":" + port;

        // 获取数据库操作
        string sql_string = z_sql == nullptr ? "unknown" : Z_STRVAL_P(z_sql);
        // vector<string> sql_str = split(sql_string, ' ');
        vector<string> sql_str = split(sql_string, " ");
        sql = sql_str[0];
        query = class_name + "->" + function_name + "::" + sql;

        // 获取错误信息
        if (IS_FALSE == Z_TYPE_P(return_value))
        {
            err = mysql->mysql->data->error_info->error;
        }

        push_db_data(addr, query, err, execute_micro_time);
    }
}

void push_mysqli_obj_handler(zend_execute_data *execute_data, zval *return_value, long execute_micro_time, string class_name, string function_name)
{
    // 初始化参数
    string ip = "127.0.0.1";
    string port = "3306";
    string addr = "";
    string sql = "";
    string err = "";
    string query = "";

    // 获取数据库连接地址
    zval mysql_link = execute_data->This;
    MY_MYSQL *mysql;
    MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_INITIALIZED);
    MYSQLND_STRING hostname = mysql->mysql->data->hostname;
    string host = hostname.s;
    int port_i = mysql->mysql->data->port;
    // vector<string> ipport = split(host, ':');
    vector<string> ipport = split(host, ":");
    ip = ipport.size() > 0 ? ipport[0] : "";
    port = to_string(port_i);
    addr = ip + ":" + port;

    // 获取sql
    uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data);
    if (arg_count)
    {
        zval *z_sql = ZEND_CALL_ARG(execute_data, 1);
        string sql_string = z_sql == nullptr ? "unknown" : Z_STRVAL_P(z_sql);
        // vector<string> sql_str = split(sql_string, ' ');
        vector<string> sql_str = split(sql_string, " ");
        sql = sql_str[0];
        query = class_name + "->" + function_name + "::" + sql;
    }

    // 获取错误信息
    if (IS_FALSE == Z_TYPE_P(return_value))
    {
        err = mysql->mysql->data->error_info->error;
    }

    push_db_data(addr, query, err, execute_micro_time);
}

void push_mysqli_stmt_handler(zend_execute_data *execute_data, zval *return_value, long execute_micro_time, string class_name, string function_name)
{
    uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data);
    if (arg_count)
    {
        // 初始化参数
        string ip = "127.0.0.1";
        string port = "3306";
        string addr = "";
        string sql = "";
        string err = "";
        string query = "";

        MY_STMT *stmt;
        zval *mysql_stmt;

        mysql_stmt = ZEND_CALL_ARG(execute_data, 1);
        if (Z_TYPE_P(mysql_stmt) != IS_OBJECT)
        {
            return;
        }

        MYSQLI_FETCH_RESOURCE_STMT(stmt, mysql_stmt, MYSQLI_STATUS_VALID);

        // 获取数据库地址
        string host = stmt->stmt->data->conn->hostname.s;
        int port_i = stmt->stmt->data->conn->port;
        // vector<string> ipport = split(host, ':');
        vector<string> ipport = split(host, ":");
        ip = ipport.size() > 0 ? ipport[0] : "";
        port = to_string(port_i);
        addr = ip + ":" + port;

        // 获取数据库操作
        int type = stmt->stmt->data->conn->last_query_type;
        uint64_t last_insert_id = stmt->stmt->data->conn->upsert_status->last_insert_id;
        switch (type)
        {
        case QUERY_UPSERT:
            sql = last_insert_id > 0 ? "insert" : "update";
            break;
        case QUERY_SELECT:
            sql = "select";
            break;
        case QUERY_LOAD_LOCAL:
            sql = "load";
            break;
        default:
            sql = "unknown";
            break;
        }
        query = class_name + "->" + function_name + "::" + sql;

        // 获取错误信息
        if (IS_FALSE == Z_TYPE_P(return_value))
        {
            err = stmt->stmt->data->conn->error_info->error;
        }

        push_db_data(addr, query, err, execute_micro_time);
    }
}

void push_mysqli_stmt_obj_handler(zend_execute_data *execute_data, zval *return_value, long execute_micro_time, string class_name, string function_name)
{
    // 初始化参数
    string ip = "127.0.0.1";
    string port = "3306";
    string addr = "";
    string sql = "";
    string err = "";
    string query = "";

    MY_STMT *stmt;
    zval mysql_stmt;

    // 获取数据库连接地址
    mysql_stmt = execute_data->This;
    MYSQLI_FETCH_RESOURCE_STMT(stmt, &mysql_stmt, MYSQLI_STATUS_VALID);
    string host = stmt->stmt->data->conn->hostname.s;
    int port_i = stmt->stmt->data->conn->port;
    // vector<string> ipport = split(host, ':');
    vector<string> ipport = split(host, ":");
    ip = ipport.size() > 0 ? ipport[0] : "";
    port = to_string(port_i);
    addr = ip + ":" + port;

    // 获取数据库操作
    int type = stmt->stmt->data->conn->last_query_type;
    uint64_t last_insert_id = stmt->stmt->data->conn->upsert_status->last_insert_id;
    switch (type)
    {
    case QUERY_UPSERT:
        sql = last_insert_id > 0 ? "insert" : "update";
        break;
    case QUERY_SELECT:
        sql = "select";
        break;
    case QUERY_LOAD_LOCAL:
        sql = "load";
        break;
    default:
        sql = "unknown";
        break;
    }
    query = class_name + "->" + function_name + "::" + sql;

    // 获取错误信息
    if (IS_FALSE == Z_TYPE_P(return_value))
    {
        err = stmt->stmt->data->conn->error_info->error;
    }

    push_db_data(addr, query, err, execute_micro_time);
}
